#pragma once
#include "Inet_data.h"
#include "SetNoBlock.h"
using namespace std;

namespace Network_module
{
    static const int g_backlog = 5;

    class Tcp
    {
    public:
        Tcp(uint16_t port)
            : _port(port)
        {
        }

        int Build_Listensocket()
        {
            // 1.网络(创建tcp listen套接字)
            Creat_socket();
            SetNoBlock(_sockfd); // 将listen套接字设置为非阻塞状态
            Bind();
            Listen();
            return _sockfd;
        }

        int Accept() // 返回一个连接套接字，用于网络数据通信
        {
            while (true)
            {
                struct sockaddr_in local;
                socklen_t len;
                int _connect_sockfd = accept(_sockfd, (sockaddr *)&local, &len);
                if (_connect_sockfd < 0)
                {
                    cout << "accept error ,continue..." << endl;
                    continue;
                }
                cout << "成功接收客户端连接..." << endl;
                Inet_data tmp(_connect_sockfd, local);
                tmp.Inet_info();

                return _connect_sockfd;
            }
        }

        bool Recv(int fd, string &buffer, int sz)
        {
            char tmp[sz];
            int n = recv(fd, tmp, sz, 0);
            if (n > 0)
            {
                tmp[n] = 0;
                buffer += tmp;
                if (buffer == "quit\r\n")
                {
                    cout << "已断开与客户端的连接..." << endl;
                    return false;
                }
                return true;
            }
            else
                return false;
        }

        uint16_t Get_sockfd()
        {
            return _sockfd;
        }

        ~Tcp()
        {
        }

    private:
        int _sockfd; // socket创建的是监听套接字，用于服务器listen
        uint16_t _port;

    private:
        void Creat_socket()
        {
            // 1.创建套接字(创建文件细节)
            _sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字(域、套接字类型、协议)参数2基本可以固定tcp/udp
            if (_sockfd < 0)
            {
                cerr << "创建套接字失败" << endl;
                exit(-1);
            }
        }

        void Bind()
        {
            // 2.绑定(网络信息与文件信息相关联)
            struct sockaddr_in local;           //
            local.sin_family = AF_INET;         // 域，用于sockaddr类型接收时的辨别字段
            local.sin_port = htons(_port);      // 端口号 主机转网络(用于发送)
            local.sin_addr.s_addr = INADDR_ANY; // 地址任意

            int n = bind(_sockfd, (sockaddr *)&local, sizeof(local));
            if (n != 0)
            {
                cerr << "套接字绑定失败!!!" << endl;
            }
        }

        void Listen() // 监听，等待客户端进行connect
        {
            if (listen(_sockfd, g_backlog) == -1) // 参数二是全连接队列
            {
                cerr << "listen fails!!!" << endl;
                exit(-1);
            }
        }
    };
}